Expand description
A Rust crate for helping parse binary data using ✨macro magic✨.
§Example
#[derive(BinRead)]
#[br(magic = b"DOG", assert(name.len() != 0))]
struct Dog {
bone_pile_count: u8,
#[br(big, count = bone_pile_count)]
bone_piles: Vec<u16>,
#[br(align_before = 0xA)]
name: NullString
}
let mut reader = Cursor::new(b"DOG\x02\x00\x01\x00\x12\0\0Rudy\0");
let dog: Dog = reader.read_ne().unwrap();
assert_eq!(dog.bone_piles, &[0x1, 0x12]);
assert_eq!(dog.name.into_string(), "Rudy")
§The Basics
At the core of binread
is the BinRead
trait. It defines how to read
a type from bytes and is already implemented for most primitives and simple collections.
use binread::{BinRead, io::Cursor};
let mut reader = Cursor::new(b"\0\0\0\x01");
let val = u32::read(&mut reader).unwrap();
However, read
is intentionally simple and, as a result, doesn’t even
allow you to configure the byte order. For that you need read_options
which, while more powerful, isn’t exactly ergonomics.
So, as a balance between ergonomics and configurability you have the BinReaderExt
trait. It is an extension for readers to allow for you to directly read any BinRead types from
any reader.
Example:
use binread::{BinReaderExt, io::Cursor};
let mut reader = Cursor::new(b"\x00\x0A");
let val: u16 = reader.read_be().unwrap();
assert_eq!(val, 10);
It even works for tuples and arrays of BinRead types for up to size 32.
§Derive Macro
The most significant feature of binread is its ability to use the Derive macro to
implement BinRead
for your own types. This allows you to replace repetitive
imperative code with declarative struct definitions for your binary data parsing.
§Basic Derive Example
#[derive(BinRead)]
struct MyType {
first: u32,
second: u32
}
// Also works with tuple types!
#[derive(BinRead)]
struct MyType2(u32, u32);
§Attributes
The BinRead derive macro uses attributes in order to allow for more complicated parsers. For
example you can use big
or little
at either the struct-level or the field-level in order
to override the byte order of values.
#[derive(BinRead)]
#[br(little)]
struct MyType (
#[br(big)] u32, // will be big endian
u32, // will be little endian
);
The order of precedence is: (from highest to lowest)
- Field-level
- Variant-level (for enums)
- Top-level
- Configured (i.e. what endianess was passed in)
- Native endianess
For a list of attributes see the attribute
module
§Generics
The BinRead derive macro also allows for generic parsing. That way you can build up higher-level parsers that can have their type swapped out to allow greater reuse of code.
#[derive(BinRead)]
struct U32CountVec<T: BinRead<Args=()>> {
count: u32,
#[br(count = count)]
data: Vec<T>,
}
In order to parse generically, we have to (in some way) bound Args
. The easiest way to do
this is to bound <T as BinRead>::Args
to ()
(no arguments), however it is also possible to
either accept a specific set of arguments or be generic over the given arguments.
§Features
const_generics
- Change arrayBinRead
implementation to use const genericsstd
- Disable this feature to enableno_std
support, on by default
Modules§
- A documentation-only module for the possible directives used in
#[br]
and#[binread]
attributes. - An enum to represent what endianness to read as
- Error types and internal error handling functions
- A wrapper type for representing a layer of indirection within a file.
- A swappable version of std::io that works in
no_std + alloc
environments. If the feature flagstd
is enabled (as it is by default), this will just re-export types fromstd::io
. - The collection of traits and types you’ll likely need when working with binread and are unlikely to cause name conflicts.
- A module for
Punctuated<T, P>
, a series of items to parse of type T separated by punction of typeP
.
Structs§
- A wrapper type for representing a layer of indirection within a file.
- A null terminated UTF-8 string designed to make reading any null-terminated data easier.
- A null terminated UTF-16 string designed to make reading any 16 bit wide null-terminated data easier.
- A wrapper where the position it was read from is stored alongside the value
- Runtime-configured options for reading the type using
BinRead
Enums§
- An enum to represent what endianness to read as
- An error while parsing a BinRead type
Traits§
- An extension trait for
io::Read
to provide methods for reading a value directly
Functions§
- A helper equivelant to
#[br(count = N)]
which can be used with any collection. - Read items until a condition is met. The final item will be included.
- Read items until the end of the file is hit.
- Read items until a condition is met. The last item will not be named.
Type Aliases§
- A Result for any binread function that can return an error
- Type alias for 8-bit pointers
- Type alias for 16-bit pointers
- Type alias for 32-bit pointers
- Type alias for 64-bit pointers
- Type alias for 128-bit pointers
Attribute Macros§
- Equivalent to
derive(BinRead)
but allows for temporary variables.
Derive Macros§
- Derive macro for BinRead. Usage here.